﻿/* Project:         ApplicationsList
 * Copyright:       Copyright (C) 2010, Rob Kennedy
 * Create Date:     2010-23-08 4:00 PM
 * Modified Date:   2010-23-08 4:00 PM
 * Comments:        2010-23-08 4:00 PM RK  Ignore SA1633
 *
 * This program is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * any later version. 
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program. If not, see <http://www.gnu.org/licenses/>. 
 */
namespace ApplicationList
{
    using System;
    using System.Collections.Generic;
    using System.Management;
    using System.Xml.Serialization;

    /// <summary>
    /// Class loads and returns a list of applications from a specified machine
    /// using WMI services
    /// </summary>
    [Serializable]
    public class ApplicationsList : List<ApplicationItem>
    {
        #region Private Properties
        /// <summary>
        /// Contains the remote machine name to connect to
        /// </summary>
        private string remoteHostName;
       
        /// <summary>
        /// Contains the user name to authenticate with
        /// </summary>
        private string userName;
        
        /// <summary>
        /// Contains the password to authenticate with
        /// </summary>
        private string password;
        
        /// <summary>
        /// Contains an error message received from connecting to host
        /// </summary>
        private string errorMessage;
        #endregion

        #region Public Constructors
        /// <summary>
        /// Initializes a new instance of the ApplicationsList class
        /// </summary>
        /// <param name="remoteHostName">Contains the host machine to connect to</param>
        /// <param name="userName">Contains the user name to authenticate with</param>
        /// <param name="password">Contains the password to authenticate with</param>
        public ApplicationsList(string remoteHostName, string userName, string password)
        {
            this.remoteHostName = remoteHostName;
            this.userName = userName;
            this.password = password;
            this.errorMessage = string.Empty;
            this.InitializeList();
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Gets any errors returned from connecting to the specified machine and loading 
        /// the applications list 
        /// </summary>
        [XmlIgnoreAttribute]
        public string ErrorMessage
        {
            get
            {
                return this.errorMessage;
            }
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Connects to the specified host and retrieves the applications, populating
        /// the list object
        /// </summary>
        private void InitializeList()
        {
            ManagementScope wmiService = null;
            ConnectionOptions wmiServiceOptions = new ConnectionOptions();
            string connectionString = string.Format("\\\\{0}\\root\\cimv2", this.remoteHostName);

            if (this.remoteHostName != "." && this.remoteHostName != "localhost" && this.userName != "$using current credentials")
            {
                wmiServiceOptions.Impersonation = ImpersonationLevel.Impersonate;
                wmiServiceOptions.Authentication = AuthenticationLevel.PacketPrivacy;
                wmiServiceOptions.Username = this.userName;
                wmiServiceOptions.Password = this.password;
                wmiService = new ManagementScope(connectionString, wmiServiceOptions);
            }
            else
            {
                wmiServiceOptions.Impersonation = ImpersonationLevel.Impersonate;
                wmiServiceOptions.Authentication = AuthenticationLevel.PacketPrivacy;
                wmiService = new ManagementScope(connectionString, wmiServiceOptions);
            }

            try
            {
                wmiService.Connect();

                if (wmiService.IsConnected)
                {
                    ObjectQuery softwareQuery = new ObjectQuery("SELECT * FROM Win32_Product");
                    ManagementObjectSearcher querySearch = new ManagementObjectSearcher(wmiService, softwareQuery);

                    // Get the results
                    ManagementObjectCollection softwareResults = querySearch.Get();
                    if (softwareResults.Count > 0)
                    {
                        foreach (ManagementBaseObject softwareItem in softwareResults)
                        {
                            ApplicationItem newItem = this.ConvertToAppItem(softwareItem);
                            if (newItem != null)
                            {
                                this.Add(newItem);
                            }
                        }
                        Console.WriteLine("placeholder");
                    }
                }
                else
                {
                    this.errorMessage = string.Format("Unable to connect to {0} as user {1}", this.remoteHostName, this.userName);
                }
            }
            catch (Exception ex)
            {
                
                this.errorMessage = ex.Message;
            }
        }

        /// <summary>
        /// Converts a returned ManagementBaseObject into an ApplicationItem object
        /// </summary>
        /// <param name="baseObject">The ManagementBaseObject to convert</param>
        /// <returns>Returns an ApplicationItem object</returns>
        private ApplicationItem ConvertToAppItem(ManagementBaseObject baseObject)
        {
            ApplicationItem resultItem = null;
            if (baseObject != null)
            {
                resultItem = new ApplicationItem();
                try
                {
                    //safe values
                    resultItem.Name = this.FixString(baseObject.Properties["Name"].Value);
                    resultItem.Caption = this.FixString(baseObject.Properties["Caption"].Value);
                    resultItem.Description = this.FixString(baseObject.Properties["Description"].Value);
                    resultItem.IdentifyingNumber = this.FixString(baseObject.Properties["IdentifyingNumber"].Value);
                    resultItem.InstallDate = this.FixString(baseObject.Properties["InstallDate"].Value);
                    //resultItem.InstallDate2 = !string.IsNullOrEmpty(resultItem.InstallDate) ? Convert.ToDateTime(resultItem.InstallDate) : DateTime.MinValue;
                    resultItem.InstallState = this.FixInteger(this.FixString(baseObject.Properties["InstallState"].Value));
                    resultItem.InstallLocation = this.FixString(baseObject.Properties["InstallLocation"].Value);
                    resultItem.SKUNumber = this.FixString(baseObject.Properties["SKUNumber"].Value);
                    resultItem.Version = this.FixString(baseObject.Properties["Version"].Value);
                    resultItem.Vendor = this.FixString(baseObject.Properties["Vendor"].Value);

                    //unsafe
                    try { resultItem.AssignmentType = this.FixInteger(this.FixString(baseObject.Properties["AssignmentType"].Value)); }
                    catch { };
                    try { resultItem.HelpLink = this.FixString(baseObject.Properties["HelpLink"].Value); }
                    catch { };
                    try { resultItem.HelpTelephone = this.FixString(baseObject.Properties["HelpTelephone"].Value); }
                    catch { };
                    try { resultItem.InstallSource = this.FixString(baseObject.Properties["InstallSource"].Value); }
                    catch { };
                    try { resultItem.Language = this.FixString(baseObject.Properties["Language"].Value); }
                    catch { };
                    try { resultItem.LocalPackage = this.FixString(baseObject.Properties["LocalPackage"].Value); }
                    catch { };
                    try { resultItem.PackageName = this.FixString(baseObject.Properties["PackageName"].Value); }
                    catch { };
                    try { resultItem.ProductID = this.FixString(baseObject.Properties["ProductID"].Value); }
                    catch { };
                    try { resultItem.RegCompany = this.FixString(baseObject.Properties["RegCompany"].Value); }
                    catch { };
                    try { resultItem.RegOwner = this.FixString(baseObject.Properties["RegOwner"].Value); }
                    catch { };
                    try { resultItem.URLInfoAbout = this.FixString(baseObject.Properties["URLInfoAbout"].Value); }
                    catch { };
                    try { resultItem.URLUpdateInfo = this.FixString(baseObject.Properties["URLUpdateInfo"].Value); }
                    catch { };
                }
                catch (Exception e1)
                {
                    if (e1.Message.ToLower().Contains("not found"))
                    {
                        
                    }
                }
            }

            return resultItem;
        }

        /// <summary>
        /// Converts values to strings, null values are returned as empty strings
        /// </summary>
        /// <param name="data">The object to convert</param>
        /// <returns>Returns a string version of the object value</returns>
        private string FixString(object data)
        {
            string resultValue = string.Empty;

            if (data != null)
            {
                resultValue = Convert.ToString(data);
            }

            return resultValue;
        }

        /// <summary>
        /// Converts a string value to an integer value
        /// </summary>
        /// <param name="data">The string value to convert to int</param>
        /// <returns>Returns integer value of string, 0 if invalid</returns>
        private int FixInteger(string data)
        {
            int resultValue = 0;

            if (data != null)
            {
                int.TryParse(data, out resultValue);
            }

            return resultValue;
        }
        #endregion
    }
}
